////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Michiel Helvensteijn                                    //
//                                                                            //
// This file is part of the Mist compiler.                                    //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// along with the Mist compiler.  If not, see <http://www.gnu.org/licenses/>. //
////////////////////////////////////////////////////////////////////////////////

#include "visitors/cppvisitor.hpp"

/******************************************************************************
 * Includes                                                                   *
 ******************************************************************************/

#include <boost/foreach.hpp>
#define foreach BOOST_FOREACH

#include <boost/format.hpp>
using boost::format;

#include <sstream>
using std::ostringstream;

#include <typeinfo>

#include <boost/algorithm/string/replace.hpp>
using boost::algorithm::replace_all_copy;

#include <boost/shared_ptr.hpp>
using boost::dynamic_pointer_cast;

#include "ast/nodetypes.hpp"
#include "visitors/visitor.hpp"
#include "visitors/expressionnavigator.hpp"
#include "visitors/universalnavigator.hpp"
#include "visitors/echovisitor.hpp"
#include "visitors/findreferencesvisitor.hpp"
#include "visitors/findtemporariesvisitor.hpp"
#include "codestream.hpp"
#include "options.hpp"
#include "assert.hpp"
#include "symboltree.hpp"

/******************************************************************************
 * CppVisitor1 class                                                          *
 ******************************************************************************/

class CppVisitor1 : public ExpressionNavigator {
	public:
		
		CppVisitor1(CodeStream& out);
		
		void visit(shared_ptr<FunctionDeclaration> node);
	
	private:
		
		CodeStream& cdout;
};

/******************************************************************************
 * CppVisitor2 class                                                          *
 ******************************************************************************/

class CppVisitor2 : public UniversalNavigator {
	public:
		
		CppVisitor2(CodeStream& out);
		
		void visit(shared_ptr<ArithmeticOperation>   node);
		void visit(shared_ptr<FunctionCall>          node);
		void visit(shared_ptr<UnaryOperation>        node);
		void visit(shared_ptr<Identifier>            node);
		void visit(shared_ptr<IntegerLiteral>        node);
		void visit(shared_ptr<BooleanLiteral>        node);
		void visit(shared_ptr<Null>                  node);
		void visit(shared_ptr<ArrayType>             node);
		void visit(shared_ptr<IntegerType>           node);
		void visit(shared_ptr<BooleanType>           node);
		void visit(shared_ptr<Assertion>             node);
		void visit(shared_ptr<IfStatement>           node);
		void visit(shared_ptr<WhileStatement>        node);
		void visit(shared_ptr<Assignment>            node);
		void visit(shared_ptr<IdAssignment>          node);
		void visit(shared_ptr<CompoundStatement>     node);
		void visit(shared_ptr<FunctionType>          node);
		void visit(shared_ptr<VoidType>              node);
		void visit(shared_ptr<VariableDeclaration>   node);
		void visit(shared_ptr<FunctionDeclaration>   node);
		void visit(shared_ptr<Subscripting>          node);
		void visit(shared_ptr<ComparisonChain>       node);
		void visit(shared_ptr<AndChain>              node);
		void visit(shared_ptr<OrChain>               node);
		void visit(shared_ptr<ImpliesChain>          node);
		void visit(shared_ptr<Declarations>          node);
		void visit(shared_ptr<ForStatement>          node);
		void visit(shared_ptr<Range>                 node);
		void visit(shared_ptr<Reference>             node);
		void visit(shared_ptr<BooleanPointerLiteral> node);
		void visit(shared_ptr<IntegerPointerLiteral> node);
	
	private:
		
		void print_value_expression(shared_ptr<Expression> node, string str = "");
		
		bool beginning() const;
		void begun();
		
		void cpp_binary_operator(Comparison comparison, string op, bool first, bool last);
		void visit_comparison(Comparison comparison, bool first, bool last);
	
	private:
		
		CodeStream& cdout;
		
		// A bool to see if we're only just in the first compound-statement
		bool _beginning;
};

void print_valuation_vector(CodeStream& cdout, shared_ptr<Assertion> node);

string to_cpp_string(ArithmeticOperator operator_type) {
	switch (operator_type) {
		case BinaryPlusOperator:     return "+";
		case BinaryMinusOperator:    return "-";
		case MultiplicationOperator: return "*";
		case DivisionOperator:       return "/";
		case ModuloOperator:         return "%";
		default: assert(false);
	}
}

string to_cpp_string(UnaryOperator operator_type) {
	switch (operator_type) {
		case NotOperator:        return "!";
		case UnaryMinusOperator: return "-";
		default: assert(false);
	}
}

/******************************************************************************
 * Function Implementations                                                   *
 ******************************************************************************/

cpp::cpp(shared_ptr<Node> tree, unsigned tabSize) : _tree(tree), _tabSize(tabSize) {
	assert(tree);
}

cpp::operator string() const {
	ostringstream sout;
	
	sout << *this;
	
	return sout.str();
}

ostream& cpp::send_to_stream(ostream& out) const {
	CodeStream cdout(out, _tabSize);
	
	shared_ptr<CppVisitor2> visitor(new CppVisitor2(cdout));
	
	_tree->accept(visitor);
	
	return out;
}

/******************************************************************************/

cppProgram::cppProgram(shared_ptr<Declarations> tree, unsigned tabSize) : _tree(tree), _tabSize(tabSize) {
	assert(tree);
}

cppProgram::operator string() const {
	ostringstream sout;
	
	sout << *this;
	
	return sout.str();
}

void output_prototypes(CodeStream& out, shared_ptr<SymbolTree> symbolTree) {
	if (typeid(*symbolTree) == typeid(NamedSymbol)) {
		shared_ptr<NamedSymbol> nsymbol(dynamic_pointer_cast<NamedSymbol>(symbolTree));
		if (typeid(*nsymbol->type()) == typeid(FunctionType)) {
			shared_ptr<FunctionType> ftype(dynamic_pointer_cast<FunctionType>(nsymbol->type()));
			
			out << cpp(ftype->return_type()) << " "
			    << to_cpp_name(nsymbol->path()) << "(";
			
			for (unsigned i = 0; i < ftype->parameter_type_count(); ++i) {
				if (i > 0)
					out << ", ";
				if (ftype->parameter_types()[i].policy->identityPassed == false && ftype->parameter_types()[i].policy->formalAccess.identity.readable) {
					// By value will always have a strong pointer formal parameter
					out << "StrongPointer<" << cpp(ftype->parameter_types()[i].type) << " >";
				} else if (ftype->parameter_types()[i].policy->identityPassed && ftype->parameter_types()[i].policy->identityReturned == false) {
					if (ftype->parameter_types()[i].type->weak_pointer())
						out << "WeakPointer";
					else
						out << "StrongPointer";
					out << "<" << cpp(ftype->parameter_types()[i].type) << " >";
				} else {
					if (ftype->parameter_types()[i].type->weak_pointer())
						out << "WeakPointer";
					else
						out << "StrongPointer";
					out << "<" << cpp(ftype->parameter_types()[i].type) << " >&";
				}
			}
			
			set<shared_ptr<NamedSymbol> > used_vars = nsymbol->used_vars_recursive_without_functions();
			
			for (set<shared_ptr<NamedSymbol> >::const_iterator i = used_vars.begin(); i != used_vars.end(); ++i) {
				if (i != used_vars.begin() || ftype->parameter_type_count() > 0)
					out << ", ";
				if ((*i)->type()->weak_pointer())
					out << "WeakPointer";
				else
					out << "StrongPointer";
				out << "<" << cpp((*i)->type()) << " >&";
			}
			
			// Special case: write(), we need to pass the location for the error message
			if (nsymbol->path() == Path("", "write", 0)) {
				out << ", const std::string&";
			}
			
			out << ");\n";
		}
	}
	
	foreach (shared_ptr<SymbolTree> child, symbolTree->children())
		output_prototypes(out, child);
}

void output_read_and_write(CodeStream& out) {
	out << "void _swrite(StrongPointer<BigInt> _swrite_sval, const std::string& location) {\n" << indent
	    <<     "std::cout << _swrite_sval.deref(\"write.val\", location) << '\\n';\n"
	    << unindent << "}\n\n";
	
	out << "BigInt _sread() {\n" << indent
	    <<     "BigInt _sread_sresult;\n"
	    <<     "std::cin >> _sread_sresult;\n"
	    <<     "return _sread_sresult;\n"
	    << unindent << "}\n\n";
}

void output_main(CodeStream& cdout, shared_ptr<Declarations> tree) {
	cdout << "int main() {\n" << indent;
	
	vector<shared_ptr<Type> > temporaries = find_temporaries(tree);
	unsigned tempCounter = 1;
	foreach (shared_ptr<Type> type, temporaries)
		cdout << "StrongPointer<" << cpp(type) << " > t" << tempCounter++ << ";\n";
	
	shared_ptr<CppVisitor2> statementVisitor(new CppVisitor2(cdout));
	tree->accept(statementVisitor);
	
	cdout << "try {\n" << indent
	      <<     "BigInt result = _srun(";
	
	set<shared_ptr<NamedSymbol> > used_vars = tree->scope()->get_local_symbol("run")->used_vars_recursive_without_functions();
	
	for (set<shared_ptr<NamedSymbol> >::const_iterator i = used_vars.begin(); i != used_vars.end(); ++i) {
		if (i != used_vars.begin())
			cdout << ", ";
		cdout << to_cpp_name((*i)->path());
	}
	
	cdout <<     ");\n"
	      <<     "if (!(0 <= result && result <= 255)) {\n" << indent
	      <<         "std::map<std::string, Valuation> valuations;\n"
	      <<         "valuations[\"result\"] = Valuation(IntegerValuation, result);\n"
	      <<         "throw AssertionFailure(\"Error:\\n    assertion (0 <= result <= 255) failed\\n\", valuations);\n"
	      <<     unindent << "}\n"
	      <<     "return result.get_si();\n" << unindent
	      << "} catch (AssertionFailure& af) {\n" << indent
	      <<     "std::cerr << af.what();\n"
	      <<     "std::pair<std::string, Valuation> val;\n"
	      <<     "BOOST_FOREACH (val, af.valuation()) {\n" << indent
	      <<         "if (val.second.nullError) {\n" << indent
	      <<             "std::cerr << \"    | \" << val.first << \" == null\\n\";\n"
	      <<         unindent << "} else {\n" << indent
	      <<             "switch (val.second.type) {\n" << indent
	      <<                 "case IntegerValuation: "
	      <<                 "std::cerr << \"    | \" << val.first << \" = \" << val.second.value << \"\\n\";"
	      <<                 "break;\n"
	      <<                 "case BooleanValuation: "
	      <<                 "std::cerr << \"    | \" << val.first << \" = \" << (val.second.value != 0 ? \"true\" : \"false\") << \"\\n\";"
	      <<                 "break;\n"
	      <<                 "case ArrayValuation: "
	      <<                 "std::cerr << \"    | \" << val.first << \" = <array>[\" << val.second.value << \"]\\n\";"
	      <<                 "break;\n"
	      <<                 "case FunctionValuation: break;\n"
	      <<             unindent << "}\n"
	      <<         unindent << "}\n"
	      <<     unindent << "}\n"
	      <<     "return 1;\n"
	      << unindent << "} catch (std::vector<AssertionFailure>& af) {\n" << indent
	      <<     "BOOST_FOREACH (AssertionFailure& a, af) {\n" << indent
	      <<         "std::cerr << a.what();\n"
	      <<         "std::pair<std::string, Valuation> val;\n"
	      <<         "BOOST_FOREACH (val, a.valuation()) {\n" << indent
	      <<             "if (val.second.nullError) {\n" << indent
	      <<                 "std::cerr << \"    | \" << val.first << \" == null\\n\";\n"
	      <<             unindent << "} else {\n" << indent
	      <<                 "switch (val.second.type) {\n" << indent
	      <<                     "case IntegerValuation: "
	      <<                     "std::cerr << \"    | \" << val.first << \" = \" << val.second.value << \"\\n\";"
	      <<                     "break;\n"
	      <<                     "case BooleanValuation: "
	      <<                     "std::cerr << \"    | \" << val.first << \" = \" << (val.second.value != 0 ? \"true\" : \"false\") << \"\\n\";"
	      <<                     "break;\n"
	      <<                     "case ArrayValuation: "
	      <<                     "std::cerr << \"    | \" << val.first << \" = <array>[\" << val.second.value << \"]\\n\";"
	      <<                     "break;\n"
	      <<                     "case FunctionValuation: break;\n"
	      <<                 unindent << "}\n"
	      <<             unindent << "}\n"
	      <<         unindent << "}\n"
	      <<     unindent << "}\n\n"
	      <<     "return 1;\n"
	      << unindent << "}\n";
	
	cdout << unindent << "}\n\n";
}

ostream& cppProgram::send_to_stream(ostream& out) const {
	CodeStream cdout(out, _tabSize);
	
	cdout << "#include <iostream>\n"
	      << "#include <vector>\n"
	      << "#include <boost/foreach.hpp>\n"
	      << "#include <boost/shared_ptr.hpp>\n"
	      << "#include <boost/weak_ptr.hpp>\n"
	      << "#include <map>\n"
	      << "#include <gmpxx.h>\n"
	      << "#include <cassert>\n"
	      << "typedef mpz_class BigInt;\n\n";
	
	cdout << "enum ValuationType {\n" << indent
	      <<     "IntegerValuation,\n"
	      <<     "BooleanValuation,\n"
	      <<     "ArrayValuation,\n"
	      <<     "FunctionValuation\n"
	      << unindent << "};\n\n"
	      << "struct Valuation {\n" << indent
	      <<     "Valuation() : nullError(true) {}\n"
	      <<     "Valuation(ValuationType t, const BigInt& v) : nullError(false), type(t), value(v) {}\n"
	      <<     "bool nullError;\n"
	      <<     "ValuationType type;\n"
	      <<     "BigInt value;\n"
	      << unindent << "};\n\n";
	
	cdout << "class AssertionFailure : public std::exception {\n" << indent
	      <<     "public:\n\n" << indent
	      <<         "AssertionFailure(const std::string& message, std::map<std::string, Valuation> valuation) : _message(message), _valuation(valuation) {\n"
	      <<         "} // intentionally empty\n\n"
	      <<         "~AssertionFailure() throw() {}\n\n"
	      <<         "const char* what() const throw() {\n" << indent
	      <<             "return _message.c_str();\n"
	      <<         unindent << "}\n\n"
	      <<         "const std::map<std::string, Valuation>& valuation() const throw() {\n" << indent
	      <<             "return _valuation;\n"
	      <<         unindent << "}\n\n"
	      <<     unindent << "private:\n\n" << indent
	      <<         "std::string _message;\n"
	      <<         "std::map<std::string, Valuation> _valuation;\n"
	      <<     unindent
	      << unindent << "};\n\n";
	
	cdout << "template <class T, unsigned size>\n"
	      << "class Array : public std::vector<T> {\n" << indent
	      <<     "public:\n" << indent
	      <<         "Array() {\n" << indent
	      <<             "for (unsigned i = 0; i < size; ++i)\n" << indent
	      <<                 "push_back(T());\n"
	      <<             unindent
	      <<         unindent << "}\n"
	      <<         "T& get(const BigInt& index, std::string location, std::string arrayName) {\n" << indent
	      <<             "if (!(0 <= index && index < size)) {\n" << indent
	      <<                 "std::map<std::string, Valuation> valuations;\n"
	      <<                 "valuations[\"index\"] = Valuation(IntegerValuation, index);\n"
	      <<                 "valuations[arrayName] = Valuation(ArrayValuation, size);\n"
	      <<                 "throw AssertionFailure(\"Error: \" + location + \"\\n    assertion (0 <= index < #\" + arrayName + \") failed\\n\", valuations);\n"
	      <<              unindent << "}\n"
	      <<             "return std::vector<T>::at(index.get_ui());\n"
	      <<         unindent << "}\n"
	      <<     unindent
	      << unindent << "};\n\n";
	
	cdout << "template<class T> class WeakPointer;\n\n";
	cdout << "template<class T> class StrongPointer;\n\n";
	cdout << "template<class T> class LogicalPointer;\n\n";
	
	cdout << "template<class T>\n"
	      << "class StrongPointer {\n" << indent
	      <<     "public:\n" << indent
	      <<         "StrongPointer();\n"
	      <<         "StrongPointer(T* pointer);\n"
	      <<         "StrongPointer(const StrongPointer<T>& pointer);\n"
	      <<         "StrongPointer(const WeakPointer<T>& pointer);\n"
	      <<         "bool is_null() const;\n"
	      <<         "T& deref(const std::string& name, const std::string& location);\n"
	      <<         "T  valderef(const std::string& name, const std::string& location);\n"
	      <<         "StrongPointer<T>& operator=(T* pointer);\n"
	      <<         "StrongPointer<T>& operator=(const StrongPointer<T>& pointer);\n"
	      <<         "StrongPointer<T>& operator=(const WeakPointer<T>& pointer);\n"
	      <<         "StrongPointer<T> get_and_then_set_null();\n"
	      <<         "mutable boost::shared_ptr<T> _p;\n"
	      <<     unindent
	      << unindent << "};\n\n";
	
	cdout << "template<class T>\n"
	      << "class WeakPointer {\n" << indent
	      <<     "public:\n" << indent
	      <<         "WeakPointer() {}\n"
	      <<         "WeakPointer(T* pointer);\n"
	      <<         "WeakPointer(const StrongPointer<T>& pointer);\n"
	      <<         "WeakPointer(const WeakPointer<T>& pointer);\n"
	      <<         "bool is_null() const;\n"
	      <<         "T& deref(const std::string& name, const std::string& location);\n"
	      <<         "T  valderef(const std::string& name, const std::string& location);\n"
	      <<         "WeakPointer<T>& operator=(T* pointer);\n"
	      <<         "WeakPointer<T>& operator=(const StrongPointer<T>& pointer);\n"
	      <<         "WeakPointer<T>& operator=(const WeakPointer<T>& pointer);\n"
	      <<         "mutable boost::weak_ptr<T> _p;\n"
	      <<     unindent
	      << unindent << "};\n\n";
	
	cdout << "template<class T>\n"
	      << "class LogicalPointer {\n" << indent
	      <<     "public:\n" << indent
	      <<         "LogicalPointer();\n"
	      <<         "LogicalPointer(T* pointer);\n"
	      <<         "LogicalPointer(const StrongPointer<T>& pointer);\n"
	      <<         "LogicalPointer(const WeakPointer<T>& pointer);\n"
	      <<         "LogicalPointer(const LogicalPointer<T>& pointer);\n"
	      <<         "bool is_null() const;\n"
	      <<         "T& deref(const std::string& name, const std::string& location);\n"
	      <<         "T  valderef(const std::string& name, const std::string& location);\n"
	      <<         "LogicalPointer<T>& operator=(T* pointer);\n"
	      <<         "LogicalPointer<T>& operator=(const StrongPointer<T>& pointer);\n"
	      <<         "LogicalPointer<T>& operator=(const WeakPointer<T>& pointer);\n"
	      <<         "LogicalPointer<T>& operator=(const LogicalPointer<T>& pointer);\n"
	      <<         "mutable T* _i;\n"
	      <<         "mutable T  _v;\n"
	      <<     unindent
	      << unindent << "};\n\n";
	
	cdout << "template <>\n"
	      << "StrongPointer<BigInt>::StrongPointer() {\n" << indent
	      <<     "_p.reset(new BigInt(\"0\"));\n"
	      << unindent << "}\n\n";
	
	cdout << "template <>\n"
	      << "StrongPointer<bool>::StrongPointer() {\n" << indent
	      <<     "_p.reset(new bool(false));\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "StrongPointer<T>::StrongPointer() {\n" << indent
	      <<     "_p.reset(new T);\n"
	      << unindent << "}\n\n";
	
	cdout << "template <>\n"
	      << "LogicalPointer<BigInt>::LogicalPointer() : _i(0) {\n" << indent
	      <<     "_v = BigInt(\"0\");\n"
	      << unindent << "}\n\n";
	
	cdout << "template <>\n"
	      << "LogicalPointer<bool>::LogicalPointer() : _i(0) {\n" << indent
	      <<     "_v = false;\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "LogicalPointer<T>::LogicalPointer() : _i(0) {\n" << indent
	      <<     "_v = T();\n"
	      << unindent << "}\n\n";
	
	cdout << "template<class T> StrongPointer<T>::StrongPointer(T* pointer) { *this = pointer; }\n"
	      << "template<class T> StrongPointer<T>::StrongPointer(const StrongPointer<T>& pointer) { *this = pointer; }\n"
	      << "template<class T> StrongPointer<T>::StrongPointer(const WeakPointer<T>& pointer) { *this = pointer; }\n"
	      << "template<class T> bool StrongPointer<T>::is_null() const { return !(bool)_p; }\n"
	      << "template<class T> T& StrongPointer<T>::deref(const std::string& name, const std::string& location) {\n" << indent
	      <<     "if (is_null()) {\n" << indent
	      <<         "std::map<std::string, Valuation> valuations;\n"
	      <<         "valuations[name] = Valuation();\n"
	      <<         "throw AssertionFailure(\"Error: \" + location + \"\\n    assertion (\" + name + \" !== null) failed\\n\", valuations);\n"
	      <<     unindent << "}\n"
	      <<     "return *_p;\n"
	      << unindent << "}\n"
	      << "template<class T> T StrongPointer<T>::valderef(const std::string& name, const std::string& location) {\n" << indent
	      <<     "return deref(name, location);\n"
	      << unindent << "}\n"
	      << "template<class T> StrongPointer<T>& StrongPointer<T>::operator=(T* pointer) { _p.reset(); if (pointer) _p.reset(pointer); return *this; }\n"
	      << "template<class T> StrongPointer<T>& StrongPointer<T>::operator=(const StrongPointer<T>& pointer) { _p = pointer._p; return *this; }\n"
	      << "template<class T> StrongPointer<T>& StrongPointer<T>::operator=(const WeakPointer<T>& pointer) { _p = pointer._p.lock(); return *this; }\n"
	      << "template<class T> StrongPointer<T> StrongPointer<T>::get_and_then_set_null() { StrongPointer<T> t(*this); _p.reset(); return t; }\n";
	
	cdout << "template<class T> WeakPointer<T>::WeakPointer(T* pointer) { *this = pointer; }\n"
	      << "template<class T> WeakPointer<T>::WeakPointer(const StrongPointer<T>& pointer) { *this = pointer; }\n"
	      << "template<class T> WeakPointer<T>::WeakPointer(const WeakPointer<T>& pointer) { *this = pointer; }\n"
	      << "template<class T> bool WeakPointer<T>::is_null() const { return _p.expired(); }\n"
	      << "template<class T> T& WeakPointer<T>::deref(const std::string& name, const std::string& location) {\n" << indent
	      <<     "if (is_null()) {\n" << indent
	      <<         "std::map<std::string, Valuation> valuations;\n"
	      <<         "valuations[name] = Valuation();\n"
	      <<         "throw AssertionFailure(\"Error: \" + location + \"\\n    assertion (\" + name + \" !== null) failed\\n\", valuations);\n"
	      <<     unindent << "}\n"
	      <<     "return *_p.lock();\n"
	      << unindent << "}\n"
	      << "template<class T> T WeakPointer<T>::valderef(const std::string& name, const std::string& location) {\n" << indent
	      <<     "return deref(name, location);\n"
	      << unindent << "}\n"
	      << "template<class T> WeakPointer<T>& WeakPointer<T>::operator=(T* pointer) { assert(false); }\n"
	      << "template<class T> WeakPointer<T>& WeakPointer<T>::operator=(const StrongPointer<T>& pointer) { _p = pointer._p; return *this; }\n"
	      << "template<class T> WeakPointer<T>& WeakPointer<T>::operator=(const WeakPointer<T>& pointer) { _p = pointer._p; return *this; }\n";
	
	cdout << "template<class T> LogicalPointer<T>::LogicalPointer(T* pointer) { *this = pointer; }\n"
	      << "template<class T> LogicalPointer<T>::LogicalPointer(const StrongPointer<T>& pointer) { *this = pointer; }\n"
	      << "template<class T> LogicalPointer<T>::LogicalPointer(const WeakPointer<T>& pointer) { *this = pointer; }\n"
	      << "template<class T> LogicalPointer<T>::LogicalPointer(const LogicalPointer<T>& pointer) { *this = pointer; }\n"
	      << "template<class T> bool LogicalPointer<T>::is_null() const { return _i == 0; }\n"
	      << "template<class T> T& LogicalPointer<T>::deref(const std::string& name, const std::string& location) {\n" << indent
	      <<     "if (is_null()) {\n" << indent
	      <<         "std::map<std::string, Valuation> valuations;\n"
	      <<         "valuations[name] = Valuation();\n"
	      <<         "throw AssertionFailure(\"Error: \" + location + \"\\n    assertion (\" + name + \" !== null) failed\\n\", valuations);\n"
	      <<     unindent << "}\n"
	      <<     "return _v;\n"
	      << unindent << "}\n"
	      << "template<class T> T LogicalPointer<T>::valderef(const std::string& name, const std::string& location) {\n" << indent
	      <<     "return deref(name, location);\n"
	      << unindent << "}\n"
	      << "template<class T> LogicalPointer<T>& LogicalPointer<T>::operator=(T* pointer) { _i = pointer; _v = *pointer; }\n"
	      << "template<class T> LogicalPointer<T>& LogicalPointer<T>::operator=(const StrongPointer<T>& pointer) { if (pointer.is_null()) { _i = 0; } else { _i = pointer._p.get(); _v = *pointer._p; } }\n"
	      << "template<class T> LogicalPointer<T>& LogicalPointer<T>::operator=(const WeakPointer<T>& pointer) { if (pointer.is_null()) { _i = 0; } else { _i = pointer._p.get(); _v = *pointer._p; } }\n"
	      << "template<class T> LogicalPointer<T>& LogicalPointer<T>::operator=(const LogicalPointer<T>& pointer) { _i = pointer._i; _v = pointer._v; }\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(StrongPointer<T> sp, WeakPointer<T> wp) {\n" << indent
	      <<     "return sp._p == wp._p.lock();"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(WeakPointer<T> wp, StrongPointer<T> sp) {\n" << indent
	      <<     "return sp._p == wp._p.lock();"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(StrongPointer<T> sp1, StrongPointer<T> sp2) {\n" << indent
	      <<     "return sp1._p == sp2._p;"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(WeakPointer<T> wp1, WeakPointer<T> wp2) {\n" << indent
	      <<     "return wp1._p.lock() == wp2._p.lock();"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(WeakPointer<T> wp, int) {\n" << indent
	      <<     "return wp.is_null();"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(StrongPointer<T> sp, int) {\n" << indent
	      <<     "return sp.is_null();"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(int, WeakPointer<T> wp) {\n" << indent
	      <<     "return wp.is_null();"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(int, StrongPointer<T> sp) {\n" << indent
	      <<     "return sp.is_null();"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(int, LogicalPointer<T> lp) {\n" << indent
	      <<     "return lp.is_null();"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(LogicalPointer<T> lp, int) {\n" << indent
	      <<     "return lp.is_null();"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(LogicalPointer<T> lp, StrongPointer<T> sp) {\n" << indent
	      <<     "return lp._i == sp._p.get() && (!lp._i || lp._v == *sp._p);"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(StrongPointer<T> sp, LogicalPointer<T> lp) {\n" << indent
	      <<     "return lp._i == sp._p.get() && (!lp._i || lp._v == *sp._p);"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(LogicalPointer<T> lp, WeakPointer<T> wp) {\n" << indent
	      <<     "return lp._i == wp._p.get() && (!lp._i || lp._v == *wp._p);"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(WeakPointer<T> wp, LogicalPointer<T> lp) {\n" << indent
	      <<     "return lp._i == wp._p.get() && (!lp._i || lp._v == *wp._p);"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "bool operator==(LogicalPointer<T> lp1, LogicalPointer<T> lp2) {\n" << indent
	      <<     "return lp1._i == lp2._i && (!lp1._i || lp1._v == lp2._v);"
	      << unindent << "}\n\n";
	
	cdout << "std::vector<BigInt > range(const BigInt & lowerBound, const BigInt & upperBound, const BigInt & step, const std::string & location) {\n" << indent
	      <<     "if (!(step != 0)) {\n" << indent
	      <<         "std::map<std::string, Valuation> valuations;\n"
	      <<         "valuations[\"step\"] = Valuation(IntegerValuation, step);\n"
	      <<         "throw AssertionFailure(\"Error: \" + location + \"\\n    assertion (step <> 0) failed\\n\", valuations);\n"
	      <<     unindent << "}\n"
	      <<     "std::vector<BigInt> result;\n"
	      <<     "for (BigInt i = (step > 0) * lowerBound + (step < 0) * upperBound; lowerBound <= i && i <= upperBound; i += step)\n" << indent
	      <<         "result.push_back(i);"
	      <<     unindent
	      <<     "return result;\n"
	      << unindent << "}\n\n";
	
	cdout << "BigInt divide(const BigInt& dividend, const BigInt& divisor, const std::string& location) {\n" << indent
	      <<     "if (!(divisor != 0)) {\n" << indent
	      <<         "std::map<std::string, Valuation> valuations;\n"
	      <<         "valuations[\"dividend\"] = Valuation(IntegerValuation, dividend);\n"
	      <<         "valuations[\"divisor\"] = Valuation(IntegerValuation, divisor);\n"
	      <<         "throw AssertionFailure(\"Error: \" + location + \"\\n    assertion (divisor <> 0) failed\\n\", valuations);\n"
	      <<      unindent << "}\n"
	      <<     "return dividend / divisor;\n"
	      << unindent << "}\n\n";
	
	cdout << "BigInt modulo(const BigInt& dividend, const BigInt& divisor, const std::string& location) {\n" << indent
	      <<     "if (!(divisor != 0)) {\n" << indent
	      <<         "std::map<std::string, Valuation> valuations;\n"
	      <<         "valuations[\"dividend\"] = Valuation(IntegerValuation, dividend);\n"
	      <<         "valuations[\"divisor\"] = Valuation(IntegerValuation, divisor);\n"
	      <<         "throw AssertionFailure(\"Error: \" + location + \"\\n    assertion (divisor <> 0) failed\\n\", valuations);\n"
	      <<      unindent << "}\n"
	      <<     "return dividend % divisor;\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "StrongPointer<T>& assign(StrongPointer<T>& leftSide, const T& rightSide, const std::string& name, const std::string& location) {\n" << indent
	      <<     "leftSide.deref(name, location) = rightSide;\n"
	      <<     "return leftSide;\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "WeakPointer<T>& assign(WeakPointer<T>& leftSide, const T& rightSide, const std::string& name, const std::string& location) {\n" << indent
	      <<     "leftSide.deref(name, location) = rightSide;\n"
	      <<     "return leftSide;\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "StrongPointer<T>& id_assign(StrongPointer<T>& leftSide, StrongPointer<T> rightSide) {\n" << indent
	      <<     "leftSide = rightSide;\n"
	      <<     "return leftSide;\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "WeakPointer<T>& id_assign(WeakPointer<T>& leftSide, WeakPointer<T> rightSide) {\n" << indent
	      <<     "leftSide = rightSide;\n"
	      <<     "return leftSide;\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "WeakPointer<T>& id_assign(WeakPointer<T>& leftSide, StrongPointer<T> rightSide) {\n" << indent
	      <<     "leftSide = rightSide;\n"
	      <<     "return leftSide;\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "StrongPointer<T>& id_assign(StrongPointer<T>& leftSide, WeakPointer<T> rightSide) {\n" << indent
	      <<     "leftSide = rightSide;\n"
	      <<     "return leftSide;\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "StrongPointer<T>& id_assign_null(StrongPointer<T>& leftSide) {\n" << indent
	      <<     "leftSide = 0;\n"
	      <<     "return leftSide;\n"
	      << unindent << "}\n\n";
	
	cdout << "template <class T>\n"
	      << "WeakPointer<T>& id_assign_null(WeakPointer<T>& leftSide) {\n" << indent
	      <<     "leftSide = 0;\n"
	      <<     "return leftSide;\n"
	      << unindent << "}\n\n";
		
	output_prototypes(cdout, _tree->scope());
	
	cdout << "\n";
	
	output_read_and_write(cdout);
	
	shared_ptr<CppVisitor1> visitor(new CppVisitor1(cdout));
	_tree->accept(visitor);
	
	output_main(cdout, _tree);
	
	return out;
}

/******************************************************************************/

CppVisitor1::CppVisitor1(CodeStream& out) : cdout(out) {
} // intentionally empty

void CppVisitor1::visit(shared_ptr<FunctionDeclaration> node) {
	assert(node);
	
	StatementNavigator::visit(node);
	
	shared_ptr<FunctionType> ftype(node->type());
	
	cdout << cpp(ftype->return_type()) << " "
	      << to_cpp_name(node->name()->symbol()->path()) << "(";
	
	for (unsigned i = 0; i < ftype->parameter_type_count(); ++i) {
		if (i > 0)
			cdout << ", ";
		if (ftype->parameter_types()[i].policy->identityPassed == false && ftype->parameter_types()[i].policy->formalAccess.identity.readable) {
			// By value always has a strong pointer formal parameter
			cdout << "StrongPointer<" << cpp(ftype->parameter_types()[i].type) << " > "
			      << to_cpp_name(node->parameter_names()[i]->symbol()->path());
		} else if (ftype->parameter_types()[i].policy->identityPassed && ftype->parameter_types()[i].policy->identityReturned == false) {
			if (ftype->parameter_types()[i].type->weak_pointer())
				cdout << "WeakPointer";
			else
				cdout << "StrongPointer";
			cdout << "<" << cpp(ftype->parameter_types()[i].type) << " > "
			      << to_cpp_name(node->parameter_names()[i]->symbol()->path());
		} else {
			if (ftype->parameter_types()[i].type->weak_pointer())
				cdout << "WeakPointer";
			else
				cdout << "StrongPointer";
			cdout << "<" << cpp(ftype->parameter_types()[i].type) << " >& "
			      << to_cpp_name(node->parameter_names()[i]->symbol()->path());
		}
	}
	
	set<shared_ptr<NamedSymbol> > used_vars = node->name()->symbol()->used_vars_recursive_without_functions();
	
	for (set<shared_ptr<NamedSymbol> >::const_iterator i = used_vars.begin(); i != used_vars.end(); ++i) {
		if (i != used_vars.begin() || ftype->parameter_type_count() > 0)
			cdout << ", ";
		if ((*i)->type()->weak_pointer())
			cdout << "WeakPointer";
		else
			cdout << "StrongPointer";
		cdout << "<" << cpp((*i)->type()) << " >& "
		      << to_cpp_name((*i)->path());
	}
	
	cdout << ") {\n" << indent;
	
	// Find temps
	vector<shared_ptr<Type> > temporaries = find_temporaries(node);
	unsigned tempCounter = 1;
	foreach (shared_ptr<Type> type, temporaries)
		cdout << "StrongPointer<" << cpp(type) << " > t" << tempCounter++ << ";\n";
	
	if (node->precondition_count() > 0) {
		cdout << "std::vector<AssertionFailure> preconditionFailures;\n";
		foreach (shared_ptr<Assertion> assertion, node->preconditions()) {
			if (assertion->condition_is_set()) {
				cdout << "if (!(" << cpp(assertion->condition()) << ")) {\n" << indent;
				print_valuation_vector(cdout, assertion);
				cdout <<     "preconditionFailures.push_back(AssertionFailure(\"Error: " << assertion->location()
				      <<     "\\n    precondition (" << echo(assertion->condition()) << ") failed\\n\", valuations));\n\n"
				      << unindent << "}\n";
			} else {
				shared_ptr<CppVisitor2> assertionVisitor(new CppVisitor2(cdout));
				assertion->accept(assertionVisitor);
			}
		}
		cdout << "if (!preconditionFailures.empty())\n" << indent
		      <<     "throw preconditionFailures;\n" << unindent;
	}
	
	if (node->type()->return_type()->equals(VoidType()) == false) {
		cdout << "StrongPointer<" << cpp(node->type()->return_type()) << " > " << to_cpp_name(node->name()->symbol()->get_local_symbol("result")->path()) << ";\n";
	}
	
	shared_ptr<CppVisitor2> statementVisitor(new CppVisitor2(cdout));
	node->statement()->accept(statementVisitor);
	
	if (node->postcondition_count() > 0) {
		cdout << "std::vector<AssertionFailure> postconditionFailures;\n";
		foreach (shared_ptr<Assertion> assertion, node->postconditions()) {
			cdout << "if (!(" << cpp(assertion->condition()) << ")) {\n" << indent;
			print_valuation_vector(cdout, assertion);
			cdout <<     "postconditionFailures.push_back(AssertionFailure(\"Error: " << assertion->location()
			      <<     "\\n    postcondition (" << echo(assertion->condition()) << ") failed\\n\", valuations));\n\n"
			      << unindent << "}\n";
		}
		cdout << "if (!postconditionFailures.empty())\n" << indent
		      <<     "throw postconditionFailures;\n" << unindent;
	}
	
	if (!node->type()->return_type()->equals(VoidType())) {
		cdout << "return " << to_cpp_name(node->name()->symbol()->get_local_symbol("result")->path()) << ".deref(\"result\", \"" << ftype->return_type()->location() << "\");\n";
	}
	
	cdout << unindent << "}\n\n";
}

/******************************************************************************/

string to_cpp_name(const Path& path) {
	assert(path.depth() > 0);
	
	string result;
	
	for (unsigned i = 0; i < path.depth(); ++i) {
		if (i > 0) result += "_s";
		result += replace_all_copy(path[i], "_", "__");
	}
	
	return result;
}

void CppVisitor2::print_value_expression(shared_ptr<Expression> node, string str) {
	if (node->type()->equals(IntegerType()))
		cdout << "BigInt";
	cdout << "(";
	
	if (str.empty()) {
		node->accept(shared_from_this());
		if (node->access_type().identity.readable) {
			// Immediately taking the value of a pointer literal will destroy the pointer
			// before the value is retrieved, so we will make a copy.
			cdout << ".valderef(\"" << echo(node) << "\", \"" << node->location() << "\")";
		}
	} else {
		cdout << str << ".get_and_then_set_null().valderef(\"\", \"\")";
	}
	
	cdout << ")";
}

void print_valuation_vector(CodeStream& cdout, shared_ptr<Assertion> node) {
	cdout << "std::map<std::string, Valuation> valuations;\n";
	
	foreach (shared_ptr<Reference> ref, find_references(node)) {
		if (typeid(*ref->symbol()->type()) == typeid(IntegerType))
			cdout << "if (!" << to_cpp_name(ref->symbol()->path()) << ".is_null())\n" << indent
			      <<     "valuations[\"" << ref->path() << "\"] = Valuation(IntegerValuation, " << to_cpp_name(ref->symbol()->path()) << ".deref(\"\", \"\"));\n"
			      << unindent << "else\n" << indent
			      <<     "valuations[\"" << ref->path() << "\"] = Valuation();\n"
			      << unindent;
		else if (typeid(*ref->symbol()->type()) == typeid(BooleanType))
			cdout << "if (!" << to_cpp_name(ref->symbol()->path()) << ".is_null())\n" << indent
			      <<     "valuations[\"" << ref->path() << "\"] = Valuation(BooleanValuation, " << to_cpp_name(ref->symbol()->path()) << ".deref(\"\", \"\"));\n"
			      << unindent << "else\n" << indent
			      <<     "valuations[\"" << ref->path() << "\"] = Valuation();\n"
			      << unindent;
		else if (typeid(*ref->symbol()->type()) == typeid(ArrayType))
			cdout << "if (!" << to_cpp_name(ref->symbol()->path()) << ".is_null())\n" << indent
			      <<     "valuations[\"" << ref->path() << "\"] = Valuation(ArrayValuation, (" + to_cpp_name(ref->symbol()->path()) + ".deref(\"\", \"\")).size());\n"
			      << unindent << "else\n" << indent
			      <<     "valuations[\"" << ref->path() << "\"] = Valuation();\n"
			      << unindent;
		else if (typeid(*ref->symbol()->type()) == typeid(FunctionType))
			cdout << "valuations[\"" << ref->path() << "\"] = Valuation(FunctionValuation, 0);\n";
		else
			assert(false);
	}
}

CppVisitor2::CppVisitor2(CodeStream& out) : cdout(out), _beginning(true) {
} // intentionally empty

void CppVisitor2::visit(shared_ptr<ArithmeticOperation> node) {
	assert(node);
	
	if (node->operator_type() == DivisionOperator) {
		cdout << "divide(";
		print_value_expression(node->left_operand());
		cdout << ", ";
		print_value_expression(node->right_operand());
		cdout << ", \"" << node->right_operand()->location() << "\""
		      << ")";
	} else if (node->operator_type() == ModuloOperator) {
		cdout << "modulo(";
		print_value_expression(node->left_operand());
		cdout << ", ";
		print_value_expression(node->right_operand());
		cdout << ", \"" << node->right_operand()->location() << "\""
		      << ")";
	} else {
		print_value_expression(node->left_operand());
		cdout << " " << to_cpp_string(node->operator_type()) << " ";
		print_value_expression(node->right_operand());
	}
}

void CppVisitor2::visit(shared_ptr<FunctionCall> node) {
	assert(node);
	
	assert(typeid(*node->base()) == typeid(Reference));
	shared_ptr<Reference> base(dynamic_pointer_cast<Reference>(node->base()));
	
	base->accept(shared_from_this());
	
	cdout << "(";
	
	assert(typeid(*base->type()) == typeid(FunctionType));
	shared_ptr<FunctionType> ftype = dynamic_pointer_cast<FunctionType>(base->type());
	for (unsigned i = 0; i < node->parameter_count(); ++i) {
		if (i > 0)
			cdout << ", ";
		
		if (ftype->parameter_types()[i].policy->identityPassed == false && ftype->parameter_types()[i].policy->formalAccess.identity.readable) { // by value
			cdout << "StrongPointer<" << cpp(ftype->parameter_types()[i].type)
			      << " >(new " << cpp(ftype->parameter_types()[i].type) << "(";
			print_value_expression(node->parameters()[i]);
			cdout << "))";
		} else if (ftype->parameter_types()[i].policy->identityPassed && ftype->parameter_types()[i].policy->identityReturned == false) { // by reference
			//if (node->parameters()[i]->equals(Null())) {
			//	cdout << "StrongPointer<";
			//	ftype->parameter_types()[i].type->accept(shared_from_this());
			//	cdout << " >()";
			//} else {
				node->parameters()[i]->accept(shared_from_this());
			//}
		} else { // by alias
			node->parameters()[i]->accept(shared_from_this());
		}
	}
	
	set<shared_ptr<NamedSymbol> > used_vars = base->symbol()->used_vars_recursive_without_functions();
	for (set<shared_ptr<NamedSymbol> >::const_iterator i = used_vars.begin(); i != used_vars.end(); ++i) {
		if (i != used_vars.begin() || node->parameter_count() > 0)
			cdout << ", ";
		cdout << to_cpp_name((*i)->path());
	}
	
	// Special case: write(), we need to pass the location for the error message
	if (base->symbol()->path() == Path("", "write", 0))
		cdout << ", \"" << node->parameters()[0]->location() << "\"";
	
	cdout << ")";
}

void CppVisitor2::visit(shared_ptr<UnaryOperation> node) {
	assert(node);
	
	if (node->operator_type() == CountOperator) {
		cdout << "BigInt(";
		print_value_expression(node->operand());
		cdout << ".size())";
	} else {
		cdout << to_cpp_string(node->operator_type());
		print_value_expression(node->operand());
	}
}

void CppVisitor2::visit(shared_ptr<Identifier> node) {
	assert(node);
	
	cdout << to_cpp_name(node->symbol()->path());
}

void CppVisitor2::visit(shared_ptr<IntegerLiteral> node) {
	assert(node);
	
	cdout << "BigInt(\"" << node->value() << "\")";
}

void CppVisitor2::visit(shared_ptr<BooleanLiteral> node) {
	assert(node);
	
	cdout << (node->value() ? "true" : "false");
}

void CppVisitor2::visit(shared_ptr<Null> node) {
	assert(node);
	
	cdout << "0";
}

void CppVisitor2::visit(shared_ptr<ArrayType> node) {
	assert(node);
	
	cdout << "Array<";
	if (node->content_type()->weak_pointer())
		cdout << "WeakPointer";
	else
		cdout << "StrongPointer";
	cdout << "<";
	node->content_type()->accept(shared_from_this());
	cdout << " >, ";
	cdout << node->size()->value();
	cdout << ">";
}

void CppVisitor2::visit(shared_ptr<IntegerType> node) {
	assert(node);
	
	cdout << "BigInt";
}

void CppVisitor2::visit(shared_ptr<BooleanType> node) {
	assert(node);
	
	cdout << "bool";
}

void CppVisitor2::visit(shared_ptr<Assertion> node) {
	assert(node);
	
	if (node->variable_declaration_is_set()) {
		foreach (VarDec var, node->variable_declaration()->variables()) {
			cdout << "LogicalPointer<";
			node->variable_declaration()->type()->accept(shared_from_this());
			cdout << " > ";
			var.name->accept(shared_from_this());
			
			if (var.is_initialized()) {
				if (var.init_is_identity) {
					cdout << "(";
					var.init->accept(shared_from_this());
					cdout << ")";
				} else {
					cdout << "(new ";
					node->variable_declaration()->type()->accept(shared_from_this());
					cdout << "(";
					print_value_expression(var.init);
					cdout << "))";
				}
			}
			cdout << ";\n";
		}
	} else if (node->condition()->equals(BooleanLiteral(true)) == false) {
		cdout << "if (!(";
		print_value_expression(node->condition());
		cdout << ")) {\n" << indent;
		print_valuation_vector(cdout, node);
		cdout <<     "throw AssertionFailure(\"Error: " << node->location()
		      <<     "\\n    assertion (" << echo(node->condition()) << ") failed\\n\", valuations);\n"
		      << unindent << "}\n";
	}
}

void CppVisitor2::visit(shared_ptr<IfStatement> node) {
	assert(node);
	
	// Condition
	cdout << "if (";
	print_value_expression(node->condition());
	cdout << ")";
	
	// Then statement
	if (typeid(*node->then_statement()) == typeid(CompoundStatement)) {
		cdout << " ";
		node->then_statement()->accept(shared_from_this());
	} else {
		cdout << "\n" << indent;
		node->then_statement()->accept(shared_from_this());
		if (   typeid(*node->then_statement()) == typeid(Assignment)
		    || typeid(*node->then_statement()) == typeid(IdAssignment)
		    || typeid(*node->then_statement()) == typeid(FunctionCall)) {
			cdout << ";";
		}
		cdout << unindent;
	}
	
	// Else statement
	if (node->else_statement_is_set()) {
		if (typeid(*node->then_statement()) == typeid(CompoundStatement))
			cdout << " else";
		else
			cdout << "\nelse";
		if (   typeid(*node->else_statement()) == typeid(CompoundStatement)
		    || typeid(*node->else_statement()) == typeid(IfStatement)) {
			cdout << " ";
			node->else_statement()->accept(shared_from_this());
		} else {
			cdout << "\n" << indent;
			node->else_statement()->accept(shared_from_this());
			if (   typeid(*node->else_statement()) == typeid(Assignment)
			    || typeid(*node->else_statement()) == typeid(IdAssignment)
			    || typeid(*node->else_statement()) == typeid(FunctionCall)) {
				cdout << ";";
			}
			cdout << unindent;
		}
	}
}

void CppVisitor2::visit(shared_ptr<WhileStatement> node) {
	assert(node);
	
	// Condition
	cdout << "while (";
	print_value_expression(node->condition());
	cdout << ")";
	
	// Statement
	if (typeid(*node->statement()) == typeid(CompoundStatement)) {
		cdout << " ";
		node->statement()->accept(shared_from_this());
	} else {
		cdout << "\n" << indent;
		node->statement()->accept(shared_from_this());
		if (   typeid(*node->statement()) == typeid(Assignment)
		    || typeid(*node->statement()) == typeid(IdAssignment)
		    || typeid(*node->statement()) == typeid(FunctionCall)) {
			cdout << ";";
		}
		cdout << unindent;
	}
}

void CppVisitor2::visit(shared_ptr<Assignment> node) {
	assert(node);
	
	cdout << "assign(";
	node->left_side()->accept(shared_from_this());
	cdout << ", ";
	print_value_expression(node->right_side());
	cdout << ", \"" << echo(node->left_side()) << "\""
	      << ", \"" << node->left_side()->location() << "\")";
}

void CppVisitor2::visit(shared_ptr<IdAssignment> node) {
	assert(node);
	
	if (node->right_side()->equals(Null())) {
		cdout << "id_assign_null(";
		node->left_side()->accept(shared_from_this());
		cdout << ")";
	} else {
		cdout << "id_assign(";
		node->left_side()->accept(shared_from_this());
		cdout << ", ";
		node->right_side()->accept(shared_from_this());
		cdout << ")";
	}
}

void CppVisitor2::visit(shared_ptr<CompoundStatement> node) {
	assert(node);
	
	bool theBeginning = beginning();
	begun();
	
	if (!theBeginning)
		cdout << "{\n" << indent;
	foreach (shared_ptr<Statement> statement, node->statements()) {
		statement->accept(shared_from_this());
		if (   typeid(*statement) == typeid(Assignment)
		    || typeid(*statement) == typeid(IdAssignment)
		    || typeid(*statement) == typeid(FunctionCall)) {
			cdout << ";";
		}
		if (   typeid(*statement) != typeid(FunctionDeclaration)
		    && typeid(*statement) != typeid(VariableDeclaration))
			cdout << "\n";
	}
	if (!theBeginning)
		cdout << unindent << "}";
}

void CppVisitor2::visit(shared_ptr<FunctionType> node) {
	// assert(node);
	assert(false); // Function type should never be printed
}

void CppVisitor2::visit(shared_ptr<VoidType> node) {
	assert(node);
	
	cdout << "void";
}

void CppVisitor2::visit(shared_ptr<VariableDeclaration> node) {
	assert(node);
	
	foreach (VarDec var, node->variables()) {
		if (node->type()->weak_pointer())
			cdout << "WeakPointer";
		else
			cdout << "StrongPointer";
		cdout << "<";
		node->type()->accept(shared_from_this());
		cdout << " > ";
		var.name->accept(shared_from_this());
		
		if (var.is_initialized()) {
			if (var.init_is_identity) {
				cdout << "(";
				var.init->accept(shared_from_this());
				cdout << ")";
			} else {
				cdout << "(new ";
				node->type()->accept(shared_from_this());
				cdout << "(";
				print_value_expression(var.init);
				cdout << "))";
			}
		}
		cdout << ";\n";
	}
}

void CppVisitor2::visit(shared_ptr<FunctionDeclaration> node) {
	assert(node);
}

void CppVisitor2::visit(shared_ptr<Subscripting> node) {
	assert(node);
	
	cdout << "(";
	node->base()->accept(shared_from_this());
	cdout << ".deref(\"" << echo(node->base()) << "\", \"" << node->base()->location() << "\")";
	cdout << ".get(";
	print_value_expression(node->subscript());
	cdout << ", \"" << to_string(node->subscript()->location()) << "\", \"" << echo(node->base()) << "\")";
	cdout << ")";
}

void CppVisitor2::visit(shared_ptr<ComparisonChain> node) {
	assert(node);
	
	for (unsigned i = 0; i < node->comparison_operator_count(); ++i) {
		if (i > 0)
			cdout << " && ";
		
		cdout << "(";
		visit_comparison(node->comparisons()[i], i == 0, i == node->comparison_operator_count() - 1);
		cdout << ")";
	}
}

void CppVisitor2::visit(shared_ptr<AndChain> node) {
	assert(node);
	
	for (unsigned i = 0; i < node->operand_count(); ++i) {
		if (i > 0)
			cdout << " && ";
		print_value_expression(node->operands()[i]);
	}
}

void CppVisitor2::visit(shared_ptr<OrChain> node) {
	assert(node);
	
	for (unsigned i = 0; i < node->operand_count(); ++i) {
		if (i > 0)
			cdout << " || ";
		print_value_expression(node->operands()[i]);
	}
}

void CppVisitor2::visit(shared_ptr<ImpliesChain> node) {
	assert(node);
	
	for (unsigned i = 0; i < node->operand_count() - 1; ++i) {
		if (i > 0)
			cdout << " && ";
		cdout << "(!";
		print_value_expression(node->implications()[i].left_operand, (i == 0 ? "" : "t" + to_string(node->implications()[i].left_operand->temp_id())));
		
		cdout << " || ";
		
		if ((   typeid(*node->implications()[i].right_operand) == typeid(Reference)
		     || typeid(*node->implications()[i].right_operand) == typeid(Subscripting)
		     || typeid(*node->implications()[i].right_operand) == typeid(BooleanPointerLiteral))
		    && node->implications()[i].right_operand->access_type().identity.readable) {
			cdout << "(";
			if (i < node->operand_count() - 2)
				cdout << "t" << to_string(node->implications()[i].right_operand->temp_id()) << " = ";
			node->implications()[i].right_operand->accept(shared_from_this());
			cdout << ").valderef(\"\", \"\")";
		} else if (i < node->operand_count() - 2) {
			cdout << "(t" << to_string(node->implications()[i].right_operand->temp_id()) << " = "
			      << "StrongPointer<" << cpp(node->implications()[i].right_operand->type()) << ">("
			      << "new " << cpp(node->implications()[i].right_operand->type()) << "(";
			print_value_expression(node->implications()[i].right_operand);
			cdout << "))).valderef(\"\", \"\")";
		} else {
			print_value_expression(node->implications()[i].right_operand);
		}
		
		cdout << ")";
	}
}

void CppVisitor2::visit(shared_ptr<Declarations> node) {
	foreach (shared_ptr<Declaration> declaration, node->declarations()) {
		declaration->accept(shared_from_this());
		if (typeid(*declaration) == typeid(VariableDeclaration))
			cdout << "\n";
	}
}

void CppVisitor2::visit(shared_ptr<ForStatement> node) {
	assert(node);
	
	cdout << format("BOOST_FOREACH(BigInt %1%, %2%)")
	         % cpp(node->iterator())
	         % cpp(node->range());
	
	// Statement
	if (typeid(*node->statement()) == typeid(CompoundStatement)) {
		cdout << " ";
		node->statement()->accept(shared_from_this());
	} else {
		cdout << "\n" << indent;
		node->statement()->accept(shared_from_this());
		if (   typeid(*node->statement()) == typeid(Assignment)
		    || typeid(*node->statement()) == typeid(IdAssignment)
		    || typeid(*node->statement()) == typeid(FunctionCall)) {
			cdout << ";";
		}
		cdout << unindent;
	}
}

void CppVisitor2::visit(shared_ptr<Range> node) {
	cdout << "range(";
	print_value_expression(node->lower_bound());
	cdout << ", ";
	print_value_expression(node->upper_bound());
	cdout << ", ";
	print_value_expression(node->step());
	cdout << ", \"" << to_string(node->step()->location()) << "\")"; // escape quotes
}

void CppVisitor2::visit(shared_ptr<Reference> node) {
	assert(node);
	
	cdout << to_cpp_name(node->symbol()->path());
}

void CppVisitor2::visit(shared_ptr<BooleanPointerLiteral> node) {
	assert(node);
	
	cdout << "StrongPointer<bool>(new bool(";
	print_value_expression(node->value());
	cdout << "))";
}

void CppVisitor2::visit(shared_ptr<IntegerPointerLiteral> node) {
	assert(node);
	
	cdout << "StrongPointer<BigInt>(new BigInt(";
	print_value_expression(node->value());
	cdout << "))";
}

/******************************************************************************/

bool CppVisitor2::beginning() const {
	return _beginning;
}

void CppVisitor2::begun() {
	_beginning = false;
}

void CppVisitor2::cpp_binary_operator(Comparison comparison, string op, bool first, bool last) {
	print_value_expression(comparison.left_operand, (first ? "" : "t" + to_string(comparison.left_operand->temp_id())));
	
	cdout << " " << op << " ";
	
	if ((   typeid(*comparison.right_operand) == typeid(Reference)
	     || typeid(*comparison.right_operand) == typeid(Subscripting)
	     || typeid(*comparison.right_operand) == typeid(BooleanPointerLiteral)
	     || typeid(*comparison.right_operand) == typeid(IntegerPointerLiteral))
		&& comparison.right_operand->access_type().identity.readable) {
		cdout << "(";
		if (!last)
			cdout << "t" << comparison.right_operand->temp_id() << " = ";
		comparison.right_operand->accept(shared_from_this());
		cdout << ").valderef(\"\", \"\")";
	} else {
		if (!last) {
			cdout << "(t" << comparison.right_operand->temp_id() << " = "
					<< "StrongPointer<" << cpp(comparison.right_operand->type()) << ">("
					<< "new " << cpp(comparison.right_operand->type()) << "(";
			print_value_expression(comparison.right_operand);
			cdout << "))).valderef(\"\", \"\")";
		} else {
			print_value_expression(comparison.right_operand);
		}
	}
}

void CppVisitor2::visit_comparison(Comparison comparison, bool first, bool last) {
	switch (comparison.comparison_operator) {
		case EqualOperator: // bool: ==, int: ==
			cpp_binary_operator(comparison, "==", first, last);
			break;
		case LessThanOperator: // bool: false, int: <
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cdout << "false";
			} else {
				cpp_binary_operator(comparison, "<", first, last);
			}
			break;
		case GreaterThanOperator: // bool: false, int: >
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cdout << "false";
			} else {
				cpp_binary_operator(comparison, ">", first, last);
			}
			break;
		case LessEqualOperator: // bool: ==, int: <=
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cpp_binary_operator(comparison, "==", first, last);
			} else {
				cpp_binary_operator(comparison, "<=", first, last);
			}
			break;
		case GreaterEqualOperator: // bool: ==, int: >=
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cpp_binary_operator(comparison, "==", first, last);
			} else {
				cpp_binary_operator(comparison, ">=", first, last);
			}
			break;
		case UnequalOperator: // bool: false, int: !=
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cdout << "false";
			} else {
				cpp_binary_operator(comparison, "!=", first, last);
			}
			break;
		case ComparableOperator: // bool: ==, int: true
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cpp_binary_operator(comparison, "==", first, last);
			} else {
				cdout << "true";
			}
			break;
		case NotEqualOperator: // bool: !=, int: !=
			cpp_binary_operator(comparison, "!=", first, last);
			break;
		case NotLessOperator: // bool: true, int: >=
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cdout << "true";
			} else {
				cpp_binary_operator(comparison, ">=", first, last);
			}
			break;
		case NotGreaterOperator: // bool: true, int: <=
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cdout << "true";
			} else {
				cpp_binary_operator(comparison, "<=", first, last);
			}
			break;
		case NotLessEqualOperator: // bool: !=, int: >
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cpp_binary_operator(comparison, "!=", first, last);
			} else {
				cpp_binary_operator(comparison, ">", first, last);
			}
			break;
		case NotGreaterEqualOperator: // bool: !=, int: <
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cpp_binary_operator(comparison, "!=", first, last);
			} else {
				cpp_binary_operator(comparison, "<", first, last);
			}
			break;
		case NotUnequalOperator: // bool: true, int: ==
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cdout << "true";
			} else {
				cpp_binary_operator(comparison, "==", first, last);
			}
			break;
		case NotComparableOperator: // bool: !=, int: false
			if (comparison.left_operand->type()->equals(BooleanType())) {
				cpp_binary_operator(comparison, "!=", first, last);
			} else {
				cdout << "false";
			}
			break;
		case IdentityOperator:
			cdout << "(";
			if (first || comparison.left_operand->equals(Null()))
				comparison.left_operand->accept(shared_from_this());
			else
				cdout << "t" << comparison.left_operand->temp_id() << ".get_and_then_set_null()";
			
			cdout << ") == (";
			
			if (!last && !comparison.right_operand->equals(Null()))
				cdout << "t" << to_string(comparison.right_operand->temp_id()) << " = ";
			comparison.right_operand->accept(shared_from_this());
			cdout << ")";
			
			break;
		case NotIdentityOperator:
			cdout << "!((";
			if (first || comparison.left_operand->equals(Null()))
				comparison.left_operand->accept(shared_from_this());
			else
				cdout << "t" << comparison.left_operand->temp_id() << ".get_and_then_set_null()";
			
			cdout << ") == (";
			
			if (!last && !comparison.right_operand->equals(Null()))
				cdout << "t" << to_string(comparison.right_operand->temp_id()) << " = ";
			comparison.right_operand->accept(shared_from_this());
			cdout << "))";
			break;
		default: assert(false);
	}
}
